賀!此系列文榮獲 2023 iThome 鐵人賽《優選》獎項,正在規劃出書中,感謝大家的支持🙏,同名課程「Java 工程師必備!Spring Boot 零基礎入門」也已在 Hahow 平台上架
哈囉大家好,我是古古
在前面的文章中,我們已經對 Spring IoC 有了滿多的認識,那麼接著這篇文章,我們會延伸出去,介紹一下要如何透過 @Value
,將 Spring Boot 設定檔中的值給讀取到 Bean 裡面
所謂的 Spring Boot 設定檔,指的是「放在 src/main/resources 這個資料夾底下的 applicaiton.properties 檔案」,而他的目的,就是去「存放 Spring Boot 程式的設定值」
大家如果點擊兩下打開 application.properties 檔案的話,可以看到右邊是空白一片,表示我們目前還沒有在這個 application.properties 檔案中,設定任何的設定值
如果想要在這個 application.properties 的檔案裡面,添加 Spring Boot 的設定值的話,需要遵循一定的寫法格式才可以
首先大家可以觀察一下,application.properties 這個檔案,他是一個「檔名為 application、並且副檔名為 .properties」的檔案,也因為如此,這個 application.properties 檔案,他就是使用**「properties 這個語法」**來撰寫的
在 properties 的語法中,是使用 key=value
這樣子的格式來撰寫,並且「每一行」都是一組 key 和 value 的配對
像是下面這個例子,我們就在第 1 行寫上了 count=5
,所以這一行程式就表示,我們定義了一個 key 的名字是 count,並且這個 count 的 value 值,就是 5
大家可以把這個 key=value
的寫法,想像成是 變數=值
的概念,所以前面的 key 其實就等同於是 Java 中的變數,而後面的 value,就是這個變數的值,就是這麼的簡單暴力!
因此當我們在 application.properties 檔案中,去寫上了一行 count=5
的程式,就表示我們定義了一個變數 count
,然後他的值是 5
這樣,僅此而已
大概了解了 properties 語法的核心概念 key=value
之後,接著我們可以來看一些使用 properties 語法的注意事項
當我們以前在寫 Java 程式的時候,習慣會在 =
的前後加上一堆空白鍵,去做排版的美化,像是下面這個樣子:
// 美化前
int count=5;
// 加上空白鍵美化後
int count = 5;
不過在 properties 語法裡面,是 「不需要」 在 =
的前後,去加上空白鍵去做排版的美化,只要全部連在一起寫就好,多加空白鍵反而可能有機會導致程式運行出現問題
所以在 properties 語法裡面,建議就是使用下面這種寫法,把你的空白鍵拔掉,一路連自連到底就對了
count=5
.
表示「的」的概念在前面有提到,properties 語法中是使用 key=value
來撰寫程式的,而 key 所代表的,就是變數的名字
不過這個 key 在命名上,是允許裡面帶上 .
符號的,並且這個 .
的符號,他的邏輯意義就是中文的「的」的意思
舉例來說,我們可以在 application.properties 檔案裡面,在第 2 行寫上 my.name=John
的程式,而當我們這樣寫之後,my.name
這個 key 就是變數的名字,其中文意義是表示「我的名字」(因為 .
是表示「的」的意思)
所以 my.name=John
這一整行的意思,就是「我的名字叫做 John」
或是我們也可以在下面,再新增一行 my.age=20
的程式,而這一行程式所代表的,就是「我的年齡是 20 歲」的意思
所以大家以後就可以將 key 中的 .
,去翻譯成是中文的「的」的意思,這樣就可以透過這種格式,去傳遞更豐富的意義出來
#
來表示 comment在 properties 語法中,也是可以去添加 comment 的,只要在最前面加上一個 #
的符號,那一行就會被 properties 語法給忽略了(用法同 Java 中的 //
一樣)
了解了要如何在 application.properties 檔案中透過 key=value
的寫法,去添加一行行的設定之後,接著我們可以來看一下,要如何透過 @Value
,將 application.properties 中的設定值讀取到 Bean 裡面
還是之前的 HpPrinter 的例子,我們可以稍微改寫一下 HpPrinter 中的程式,讓他變成下面這個樣子
@Component
public class HpPrinter implements Printer {
private int count;
@Override
public void print(String message) {
count--;
System.out.println("HP印表機: " + message);
System.out.println("剩餘使用次數: " + count);
}
}
而在這之中,count 變數的值沒有被設定成任何一個數字,因此 count 值就會是預設的 0
但是如果我們在這個 count 的變數上面,去添加一個 @Value("${count}")
的話,這樣子就可以從 Spring Boot 設定檔 (application.properties 檔案) 中,去讀取其中的 count
這個 key 的值,並且將這個值給賦予到 HpPrinter 中的 count 變數裡面
而因為目前在 application.properties 檔案中,我們是在第 1 行,去寫上了 count=5
的設定
因此到時候 HpPrinter 中的 count 變數的值,就會變成是 application.properties 檔案中所定義的「5」
所以這也就表示,我們就成功的透過 @Value
的用法,將 Spring Boot 設定檔 (application.properties 檔案) 中的值,給成功的讀取到 Bean 裡面的變數中了!
大概了解了 @Value
的用法之後,我們可以來看一下使用 @Value
的一些注意事項
在使用 @Value
去讀取 Spring Boot 設定檔 (application.properties 檔案) 中的值的時候,一定要在 @Value
後面的括號中,寫上如下的格式:
@Value("${XXXX}")
其中 XXXX 可以替換成 application.properties 檔案中的任意一個 key,但是外層的 "${}"
是不能夠省略的,因此在寫法上會稍微複雜一點,建議大家之後可以直接複製貼上這段程式,再去改裡面的 XXX 的值即可
舉例來說,假設 application.properties 中的 key 為 printer.count
printer.count=100
那麼在使用 @Value
去注入時,就是把後面的 XXX 替換成 printer.count
,所以就會變成是:
@Value("${printer.count}")
private int count;
因此就可以透過這樣的寫法,將 application.properties 中的設定值,給注入到 Bean 中的變數了
只要是有使用到 @Value
的地方,該 class 本身得是一個 Bean、或是一個 Configuration 的設定 class,@Value
才能夠生效
所以假設大家在使用 @Value
時,明明程式就寫得很對,但是不知道為什麼他不起作用,很大的原因就是因為這個 class 還沒變成 Bean,所以 @Value
才會毫無作用
因此發生這種情況時,只要記得在 class 上面加上一個 @Component
,將這個 class 變成是一個 Bean,這樣子就可以確保 @Value
能生效了
補充:
@Value
在那些帶有@Configuration
的 class 中,也是能夠生效的,不過因為在此系列文中不會特別介紹到@Configuration
的用法,所以大家可以先有個印象就可以了
在使用 @Value
去讀取 Spring Boot 設定檔 (application.properties 檔案) 中的值時,Java 中的變數的類型,必須要和 application.properties 中的類型一致才可以
舉例來說,在 application.properties 檔案裡面,我們定義了一組 key 和 value 如下:
printer.count=5
上面這行程式,其實就是在暗示 printer.count
的值為「一個整數」,因此在 Spring Boot 程式中,我們就得將 @Value
加在一個「Int 或是 Long 類型」的變數上,這樣子在賦予值的時候才不會出現問題
@Value("${printer.count}")
private int count;
又或是說,假設我們在 application.properties 檔案裡面,定義了另一組 key 和 value 如下:
my.name=John
上面這行程式,也是在暗示 my.name
的值為「一個字串」,因此在 Spring Boot 程式中,我們就得將 @Value
加在一個「String 類型」的變數上,這樣子在賦予值的時候,也才不會出現問題
@Value("${my.name}")
private String name;
在使用 @Value
去讀取 Spring Boot 設定檔 (application.properties 檔案) 中的值時,有可能會發生一種情況,就是「該 key 不存在在 application.properties 檔案裡面」
譬如說我們在 Spring Boot 程式裡面,寫上了下面這一段程式,嘗試去將 application.properties 檔案中的 printer.count
的值,去儲存到 count 變數中
@Value("${printer.count}")
private int count;
如果這時候 application.properties 檔案中「沒有」printer.count
這個 key 的話,那麼 Spring Boot 程式就會運作失敗,出現「Could not resolve placeholder 'printer.count' in value "${printer.count}"」的錯誤,導致無法成功啟動
如果大家想要避免這個問題的話,@Value
也是有提供另一種輔助方式可以讓我們使用,即是「設定預設值」
我們可以在 @Value
的 key 的後面,加上一個 :
,並且在後面寫上想要的值,譬如說這裡寫上 200
@Value("${printer.count:200}")
private int count;
上面這一段程式的意思是:「@Value
會先去找尋 application.properties 中有沒有 printer.count
這個 key,有的話,就去讀取那個 key 的值到 count 變數中,如果沒有的話,則將 count 變數的值,設定成預設的 200」
所以當我們這樣寫之後,如果 application.properties 中「有設定」printer.count
的值(如下方程式所示),那麼 Spring Boot 程式中的 count 變數的值就會是 5
printer.count=5
但是如果 application.properties 中,「沒有設定」printer.count
的值(如下方程式所示),那麼 Spring Boot 程式中的 count 變數的值就會是預設的 200
# no key-value
所以簡單的說的話,如果想要「避免 application.properties 中找不到該 key,導致 Spring Boot 程式運行失敗」的狀況的話,那麼就可以在 @Value
中使用 :
,在後面加上預設值,當找不到 key 時,就可以直接無縫接軌改成使用預設值來運行
補充:使用
@Value
的預設值寫法,其實是有點雙面刃的做法,因為這樣會讓設定值四散在各處,後續會比較難進行管理,因此建議大家斟酌使用
所以說到這邊,我們可以來總結一下 @Value
的用法和注意事項
想要使用 @Value
去讀取 Spring Boot 設定檔 (application.properties 檔案) 中的值的話,必須滿足:
@Value("${XXXX}")
只要注意好這些地方,大家以後就可以透過 @Value
,在 Spring Boot 程式中去讀取 Spring Boot 設定檔 (application.properties 檔案) 中的值了!
在前面我們有介紹到,Spring Boot 的設定檔所指的,就是「application.properties」這個檔案,而他裡面所放的,就是 Spring Boot 程式的設定值
不過其實 Spring Boot 設定檔,是可以使用兩種不同的語法來撰寫的,分別是 properties 和 yml
key=value
key: value
所以在 Spring Boot 程式裡面,application.properties 和 application.yml 這兩個檔案,他們的目的都是一樣的,都是去作為 Spring Boot 的設定檔,去儲存相關的設定值,差別只在他們使用了不同的語法來撰寫而已
不過在這裡要特特特特別注意的一點,就是 「一份 Spring Boot 程式中只能使用一種語法來撰寫」,換句話說的話,就是 application.properties 和 application.yml 這兩個檔案,他們「不能同時存在」
所以一開始在創建 Spring Boot 程式時,要不就是選用 application.properties 寫到底,要不就是使用 appilcation.yml 寫到底,不能夠讓這兩個檔案同時並存,否則會使得 Spring Boot 程式運作失敗,這是大家在使用上要特別注意的地方
補充:我自己是比較喜歡使用 application.properties 來設定,yml 語法寫起來感覺很容易出錯😂(一個恍神不小心縮排就毀了),供大家參考
在前面我們有詳細介紹了 properties 語法的用法,而這裡也可以來補充一些 yml 語法的寫法
在 yml 語法中,是採用 key: value
的方式來撰寫,注意在 value 前面 「必須」 加上一個空白鍵來隔開 :
,所以寫起來的效果如下
count: 5
上面這一段程式所表示的,就是去宣告一個 key 為 count,並且他的值為 5,而如果想用 properties 語法來表示同樣的效果的話,則會寫成下面這樣子:
count=5
yml 除了使用 key: value
的方式來設定值之外,並且 yml 是使用「縮排」的方式,來表示中文的「的」的概念
像是在 properties 語法中,當我們寫了下面這行程式,其中文意義是表示「我的名字叫做 John」(因為 properties 語法中的 .
,就是表示中文的「的」的意思)
my.name=John
而在 yml 中,則會寫成下面這個樣子,透過 「將 name 這一行往右縮排 2 個空白鍵」,表示中文的「的」的意思
my:
name: John
所以上面這一段程式讀起來,一樣也是「我的名字是 John」,只是 yml 是透過縮排的方式來表達,而 properties 是使用 .
的方式來表達而已
下面總結了 properties 語法和 yml 語法在寫法上的差別,基本上是大同小異,就是「縮排」的這個概念需要轉換一下,其他部分(像是 key 和 value 的寫法),大致上都還是滿相似的
這篇文章先介紹了什麼是 Spring Boot 的設定檔,也介紹了 application.properties 檔案的用途,以及 properties 的語法介紹
並且我們也介紹到,要如何使用 @Value
,將 Spring Boot 設定檔 (application.properties 檔案) 中的值讀取到 Bean 裡面,也介紹了使用 @Value
的注意事項和預設值的用法
最後則是補充了 Spring Boot 設定檔的兩種命名方式,也介紹了 yml 的語法,以及 properties 語法和 yml 語法的差別
所以到這篇文章為止,有關於 Spring IoC 的介紹就告一個段落了,在這個章節中:
@Component
、@Autowired
、@Qualifier
以及 @PostConstruct
這些註解,去對 Bean 進行創建、注入、以及初始化@Value
,將 Spring Boot 設定檔中的值讀取到 Bean 裡面那麼從下一篇文章開始,我們就會來了解 Spring 框架中的另一個也很重要的特性:AOP,那我們就下一篇文章見啦!
有一段有寫筆誤:
去寫上 @Value(${mycount}) 這段程式
這段少了一對雙引號喔!
去寫上 @Value("${mycount}") 這段程式
感謝提醒!已修正